using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using AntEater.ComponentModel.BuildElements;
using System.Globalization;

namespace AntEater.Runtime.UI
{

    /// <summary>
    /// Represents the Method that will resolve the ImageKey for a BuildElement.
    /// </summary>
    /// <param name="buildElement">The BuildElement for which to resolve the ImageKey.</param>
    /// <returns>The ImageKey for the specified BuildElement.</returns>
    public delegate string TreeNodeImageKeyResolver(IBuildElement buildElement);

    /// <summary>
    /// Provides a tree node that represents a build element.
    /// </summary>
    internal class BuildElementTreeNode:TreeNode
    {

        /// <summary>
        /// This Event is raised when the Child Nodes of this node have to be Recreated
        /// </summary>
        public event EventHandler<EventArgs> NeedRecreateChildNodes;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:BuildElementTreeNode"/> class.
        /// </summary>
        /// <param name="buildElement">The build element.</param>
        /// <param name="imageKeyResolver">The image key resolver.</param>
        public BuildElementTreeNode(IBuildElement buildElement, TreeNodeImageKeyResolver imageKeyResolver) {
            
            if (buildElement == null) { throw new ArgumentNullException("buildElement"); }
            if (imageKeyResolver == null) { throw new ArgumentNullException("imageKeyResolver"); }

            this._buildElement = buildElement;
            this._imageKeyResolver = imageKeyResolver;

            this._buildElement.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(BuildElementPropertyChanged);

            //If the BuildElement is a Container, listen to Changed Events of the collection to rebuild the child nodes if needed
            IContainerBuildElement container = this._buildElement as IContainerBuildElement;

            if (container != null) {
                container.ChildElements.CollectionChanged += new EventHandler<System.ComponentModel.CollectionChangeEventArgs>(ChildElementsCollectionChanged);
            }

            this.Refresh();
        }

        private IBuildElement _buildElement;

        /// <summary>
        /// Gets or sets the build element.
        /// </summary>
        /// <value>The build element.</value>
        public IBuildElement BuildElement {
            get { return _buildElement; }
        }

        private TreeNodeImageKeyResolver _imageKeyResolver;

        /// <summary>
        /// Gets the image key resolver.
        /// </summary>
        /// <value>The image key resolver.</value>
        public TreeNodeImageKeyResolver ImageKeyResolver {
            get { return _imageKeyResolver; }
        }

        /// <summary>
        /// Refreshes this instance.
        /// </summary>
        public void Refresh() {
            this.Name = this.BuildElement.GetHashCode().ToString(CultureInfo.CurrentCulture);
            this.Text = this.BuildElement.ToString();
            this.ToolTipText = ComponentModel.Utilities.GetBuildElementToolTipText(this.BuildElement);
            this.ImageKey = this.ImageKeyResolver(this.BuildElement);
            this.SelectedImageKey = this.ImageKey;
        }

        /// <summary>
        /// Called when [need recreate child nodes].
        /// </summary>
        protected void OnNeedRecreateChildNodes() {
            if (this.NeedRecreateChildNodes != null) {
                this.NeedRecreateChildNodes(this, new EventArgs());
            }
        }

        /// <summary>
        /// Builds the element property changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="T:System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        private void BuildElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) {
            this.Refresh();
        }

        /// <summary>
        /// Childs the elements collection changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="T:System.ComponentModel.CollectionChangeEventArgs"/> instance containing the event data.</param>
        private void ChildElementsCollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs e) {
            this.OnNeedRecreateChildNodes();
        }

    }
}
